package render;

import math.Maths;
import util.Bitmap;

public class RasterizerIncr extends RasterizerBase {
    
    public RasterizerIncr(int imgWidth, int imgHeight, int[] pxs) {
        super(imgWidth, imgHeight, pxs);
    }
    
    public void triFillIncr(
            float x0, float y0, float z0, 
            float x1, float y1, float z1, 
            float x2, float y2, float z2, int color) 
    {
        if (y0 > y1) { // Swap v0, v1
            float tx = x1;  x1 = x0;    x0 = tx;
            float ty = y1;  y1 = y0;    y0 = ty;
            float tz = z1;  z1 = z0;    z0 = tz;
        }
        if (y0 > y2) { // Swap v0, v2
            float tx = x2;  x2 = x0;    x0 = tx;
            float ty = y2;  y2 = y0;    y0 = ty;
            float tz = z2;  z2 = z0;    z0 = tz;
        }
        if (y1 > y2) { // Swap v1, v2
            float tx = x2;  x2 = x1;    x1 = tx;
            float ty = y2;  y2 = y1;    y1 = ty;
            float tz = z2;  z2 = z1;    z1 = tz;
        }
        
        float dz01 = (z1 - z0);
        float dz02 = (z2 - z0);
        float dz12 = (z2 - z1);
        float dy01 = (y1 - y0);
        float dy02 = (y2 - y0);
        float dy12 = (y2 - y1);
        float dx01 = (x1 - x0);
        float dx02 = (x2 - x0);
        float dx12 = (x2 - x1);
        
        float xL = x0;
        float xR = x0;
        float zL = z0;
        float zR = z0;
        
        float slopeX01 = (dx01 / dy01);
        float slopeX02 = (dx02 / dy02);
        float slopeX12 = (dx12 / dy12);
        float slopeZ01 = (dz01 / dy01);
        float slopeZ02 = (dz02 / dy02);
        float slopeZ12 = (dz12 / dy12);
        
        for (float y = y0; y < y2; y++) {
            xR += slopeX02;
            zR += slopeZ02;
            if (y >= y1) { // Below the y1 horizontal
                xL += slopeX12;
                zL += slopeZ12;
            } else { // Above the y1 horizontal
                xL += slopeX01;
                zL += slopeZ01;
            }
            lineHorizFillIncr(xL, xR, y, zL, zR, color);
        }
    }
    
    public void lineHorizFillIncr(float xL, float xR, float y, float zL, float zR, int color) {
        if (xL > xR) {
            float tx = xR;  xR = xL;    xL = tx;
            float tz = zR;  zR = zL;    zL = tz;
        }
        float slopeZLR = (zR - zL) / (xR - xL);
        float z = zL;
        int xint;
        int yint = (int)y;
        int indPx;
        for (float x = xL; x < xR; x++) {
            xint = (int)x;
            z += slopeZLR;
            indPx = getPixelIndex(xint, yint);
            if (shouldPixelAt(indPx, xint, z)) {
                pixel(indPx, z, color);
            }
        }
    }
    
    public void triBitmapIncr(
            int x0, int y0, float z0, float s0, float t0,
            int x1, int y1, float z1, float s1, float t1,
            int x2, int y2, float z2, float s2, float t2, Bitmap bmp) 
    {
        if (y0 > y1) { // Swap v0, v1
            int tx = x1;    x1 = x0;    x0 = tx;
            int ty = y1;    y1 = y0;    y0 = ty;
            float tz = z1;    z1 = z0;    z0 = tz;
            float ts = s1;    s1 = s0;    s0 = ts;
            float tt = t1;    t1 = t0;    t0 = tt;
        }
        if (y0 > y2) { // Swap v0, v2
            int tx = x2;    x2 = x0;    x0 = tx;
            int ty = y2;    y2 = y0;    y0 = ty;
            float tz = z2;    z2 = z0;    z0 = tz;
            float ts = s2;    s2 = s0;    s0 = ts;
            float tt = t2;    t2 = t0;    t0 = tt;
        }
        if (y1 > y2) { // Swap v1, v2
            int tx = x2;    x2 = x1;    x1 = tx;
            int ty = y2;    y2 = y1;    y1 = ty;
            float tz = z2;    z2 = z1;    z1 = tz;
            float ts = s2;    s2 = s1;    s1 = ts;
            float tt = t2;    t2 = t1;    t1 = tt;
        }
        
        float rec_dy01 = 1.0f / (y1 - y0);
        float rec_dy02 = 1.0f / (y2 - y0);
        float rec_dy12 = 1.0f / (y2 - y1);
        float dz01 = (z1 - z0);
        float dz02 = (z2 - z0);
        float dz12 = (z2 - z1);
        float dx01 = (x1 - x0);
        float dx02 = (x2 - x0);
        float dx12 = (x2 - x1);
        float ds01 = (s1 - s0);
        float ds02 = (s2 - s0);
        float ds12 = (s2 - s1);
        float dt01 = (t1 - t0);
        float dt02 = (t2 - t0);
        float dt12 = (t2 - t1);
        
        float slopeX01 = (dx01 * rec_dy01);
        float slopeX02 = (dx02 * rec_dy02);
        float slopeX12 = (dx12 * rec_dy12);
        float slopeS01 = (ds01 * rec_dy01);
        float slopeS02 = (ds02 * rec_dy02);
        float slopeS12 = (ds12 * rec_dy12);
        float slopeT01 = (dt01 * rec_dy01);
        float slopeT02 = (dt02 * rec_dy02);
        float slopeT12 = (dt12 * rec_dy12);
        float slopeZ01 = (dz01 * rec_dy01);
        float slopeZ02 = (dz02 * rec_dy02);
        float slopeZ12 = (dz12 * rec_dy12);
        
        float xL = x0;
        float xR = x0;
        float zL = z0;
        float zR = z0;
        float sL = s0;
        float sR = s0;
        float tL = t0;
        float tR = t0;
        
        for (float y = y0; y < y2; y++) {
            xR += slopeX02;
            zR += slopeZ02;
            sR += slopeS02;
            tR += slopeT02;
            if (y >= y1) { // Below the y1 horizontal
                xL += slopeX12;
                zL += slopeZ12;
                sL += slopeS12;
                tL += slopeT12;
            } else { // Above the y1 horizontal
                xL += slopeX01;
                zL += slopeZ01;
                sL += slopeS01;
                tL += slopeT01;
            }
            lineHorizTexIncr(xL, xR, y, zL, zR, sL, sR, tL, tR, bmp);
        }
    }
    
    public void lineHorizTexIncr(
            float xL, float xR, 
            float y, 
            float zL, float zR, 
            float sL, float sR, 
            float tL, float tR, Bitmap bmp)
    {
        if (xL == xR) {
            return;
        } else if (xL > xR) {
            float tx = xR;    xR = xL;    xL = tx;
            float tiz = zR;  zR = zL;    zL = tiz;
            float ts = sR;  sR = sL;    sL = ts;
            float tt = tR;  tR = tL;    tL = tt;
        }
        float rec_dxLR = 1.0f / (xR - xL);
        float slopeSLR = (sR - sL) * rec_dxLR;
        float slopeTLR = (tR - tL) * rec_dxLR;
        float slopeZLR = (zR - zL) * rec_dxLR;
        float z = zL;
        float s = sL;
        float t = tL;
        int xint;
        int yint = (int)y;
        int xsrc;
        int ysrc;
        int indPx;
        for (float x = xL; x < xR; x++) {
            xint = (int)x;
            z += slopeZLR;
            s += slopeSLR;
            t += slopeTLR;
            indPx = getPixelIndex(xint, yint);
            if (shouldPixelAt(indPx, xint, z)) {
                xsrc = Maths.capi((int)(s * bmp.wi), 0, bmp.wi);
                ysrc = Maths.capi((int)(t * bmp.hi), 0, bmp.hi);
                pixel(indPx, z, bmp.pixels[xsrc + bmp.w * ysrc]);
            }
        }
    }
    
}
